﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LinkGame.Models.Variations
{
    /// <summary>
    /// 表示一个控制棋盘卡片移动的变体。
    /// </summary>
    internal abstract class ApplicableVariation : IVariation
    {
        public bool ShouldApply => true;

        public void Apply(Map map, Point p1, Point p2)
        {
            if (p1.X < 0 || p1.X >= map.Width || p1.Y < 0 || p1.Y >= map.Height ||
                p2.X < 0 || p2.X >= map.Width || p2.Y < 0 || p2.Y >= map.Height)
                return;

            DoApply(map, p1, p2);
        }

        protected abstract void DoApply(Map map, Point p1, Point p2);

        protected void MoveTilesOnPoint(Map map, Point p, MovingDirection direction, int? minX = null, int? minY = null, int? maxX = null, int? maxY = null)
        {
            int cx, cy;
            minX ??= 0;
            minY ??= 0;
            maxX ??= map.Width;
            maxY ??= map.Height;
            switch (direction)
            {
                case MovingDirection.Left:
                    for (cx = p.X + 1; cx < maxX; cx++)
                    {
                        var val = map.GetTileValue(cx, p.Y);
                        map.SetTileValue(cx - 1, p.Y, val);
                    }

                    map.SetTileValue(cx - 1, p.Y);
                    break;
                case MovingDirection.Right:
                    for (cx = p.X - 1; cx >= minX; cx--)
                    {
                        var val = map.GetTileValue(cx, p.Y);
                        map.SetTileValue(cx + 1, p.Y, val);
                    }

                    map.SetTileValue(cx + 1, p.Y);
                    break;
                case MovingDirection.Up:
                    for (cy = p.Y + 1; cy < maxY; cy++)
                    {
                        var val = map.GetTileValue(p.X, cy);
                        map.SetTileValue(p.X, cy - 1, val);
                    }

                    map.SetTileValue(p.X, cy - 1);
                    break;
                case MovingDirection.Down:
                    for (cy = p.Y - 1; cy >= minY; cy--)
                    {
                        var val = map.GetTileValue(p.X, cy);
                        map.SetTileValue(p.X, cy + 1, val);
                    }

                    map.SetTileValue(p.X, cy + 1);
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(direction), direction, null);
            }
        }
    }
}
